package org.wheel.plugins.starter.jdbc.pool.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

import java.util.Arrays;
import java.util.List;

/**
 * 注册 Dao 代理类
 */
public class DaoRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware, PriorityOrdered {

    // 直接使用 LogFactory 创建日志对象，Hutool 会自动检测项目中的日志框架（优先级：Slf4j > Log4j > Logback > JDK Logging）
    private static final Log log = LogFactory.get();

    private Environment environment;

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    /**
     * 注册 Dao 代理类
     * Dao 代理类从以下路径扫描：
     * 1. 启动类所在包
     * 2. 启动类注解中配置的包路径
     * 3. application.properties/yml 中配置的包路径
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        log.trace("开始注册 Dao 代理类...");
        if (registry instanceof ConfigurableListableBeanFactory) {
            // 1. 拿到 SpringBoot 计算后的包列表 这个包是启动类所在的包根路径
            List<String> packages = AutoConfigurationPackages.get((BeanFactory) registry);
            // 2. 获取启动类，从启动类注解中获取扫描包路径
            String startupClassName = findStartupClass(registry);
            if(StrUtil.isNotBlank(startupClassName)) {
                extractPackagesFromStartupClass(startupClassName, packages);
            }

            // 3. 从 Environment 获取配置
            extractPackagesFromEnvironment(packages);

            // 4. 扫描并注册
            CustomClassPathScanningCandidateComponentProvider scanner = new CustomClassPathScanningCandidateComponentProvider(registry);
            scanner.registerDefaultFilters();
            scanner.scan(packages.stream().distinct().toList().toArray(new String[0]));
        }else{
            throw new IllegalStateException("BeanFactory is not a ConfigurableListableBeanFactory");
        }
    }


    /**
     * 从 Environment 提取包配置
     */
    private void extractPackagesFromEnvironment(List<String> packageList) {
        // 从 application.properties/yml 获取配置
        String packagesFromProps = environment.getProperty("system.default.dao.dao-scan-packages");
        if (packagesFromProps != null) {
            packageList.addAll(Arrays.asList(packagesFromProps.trim().split(",")));
        }
    }
    /**
     * 从启动类提取包配置
     * @param startupClassName 启动类名
     * @param packageList 包列表
     */
    private void extractPackagesFromStartupClass(String startupClassName, List<String> packageList) {
        try {
            Class<?> startupClass = Class.forName(startupClassName);

            // 检查启动类上的自定义注解
            if (!startupClass.isAnnotationPresent(SpringBootApplication.class)) {
                return;
            }
            SpringBootApplication annotation = startupClass.getAnnotation(SpringBootApplication.class);

            // 获取 basePackages
            if (annotation.scanBasePackages().length > 0) {
                packageList.addAll(Arrays.asList(annotation.scanBasePackages()));
            }
            // 获取 ComponentScan
            ComponentScan scan = startupClass.getAnnotation(ComponentScan.class);
            if(scan!=null && scan.basePackages().length > 0){
                packageList.addAll(Arrays.asList(scan.basePackages()));
            }

            // 如果没有显式配置包路径，使用启动类所在的包
            if (packageList.isEmpty()) {
                packageList.add(startupClass.getPackage().getName());
            }
        } catch(ClassNotFoundException e){
            System.err.println("无法解析启动类注解: " + startupClassName);
        }
    }

    /**
     * 查找启动类（带 @SpringBootApplication 注解的类）
     */
    private String findStartupClass(BeanDefinitionRegistry registry) {
        String[] beanNames = registry.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
            if (beanDefinition instanceof AnnotatedBeanDefinition annotatedDef) {
                AnnotationMetadata metadata = annotatedDef.getMetadata();
                // 检查是否是启动类
                if (metadata.hasAnnotation("org.springframework.boot.autoconfigure.SpringBootApplication")) {
                    return metadata.getClassName();
                }
            }
        }
        return null;
    }

    @Override
    public int getOrder() {
        return 2;
    }
}
